package com.yzq.service.impl;

import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yzq.enums.BusinessType;
import com.yzq.enums.ErrorCode;
import com.yzq.enums.VerificationCodeStatus;
import com.yzq.exception.BusinessException;
import com.yzq.mapper.VerificationCodeMapper;
import com.yzq.model.entity.VerificationCode;
import com.yzq.service.VerificationCodeService;
import com.yzq.utils.AliyunSmsUtils;
import com.yzq.utils.MailUtils;
import com.yzq.utils.ThrowUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/**
* @author yezhi
* @description 针对表【verification_code(验证码表)】的数据库操作Service实现
* @createDate 2025-06-29 07:57:44
*/
@Slf4j
@Service
public class VerificationCodeServiceImpl extends ServiceImpl<VerificationCodeMapper, VerificationCode>
    implements VerificationCodeService{


    @Resource
    private AliyunSmsUtils aliyunSmsUtils;

    @Resource
    private MailUtils mailUtils;

    @Resource
    private VerificationCodeMapper verificationCodeMapper;

    /**
     * 发送验证码
     * @param userIdentifier 用户标识
     * @param businessType 业务类型
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sendVerificationCode(String userIdentifier, BusinessType businessType) {
        ThrowUtils.throwIf(StrUtil.isBlank(businessType.getCode()), ErrorCode.BAD_REQUEST);
        checkUserIdentifier(userIdentifier);
        String code = RandomUtil.randomNumbers(6);
        if(Validator.isMobile(userIdentifier)) {
            aliyunSmsUtils.sendSms(userIdentifier, code);
        } else if(Validator.isEmail(userIdentifier)) {
            mailUtils.sendHtmlMail(userIdentifier, "验证码", code);
        } else {
            throw new BusinessException(ErrorCode.BAD_REQUEST);
        }
        // 保存验证码
        VerificationCode verificationCode = new VerificationCode();
        verificationCode.setUserIdentifier(userIdentifier);
        verificationCode.setCode(code);
        verificationCode.setSendTime(new Date());
        verificationCode.setStatus(VerificationCodeStatus.UNUSED);
        verificationCode.setBusinessType(businessType.getCode());
        log.info("保存验证码: {}", verificationCode);
        verificationCodeMapper.insert(verificationCode);
    }

    // 定时任务：每5分钟清理一次过期验证码
    @Scheduled(fixedRate = 5 * 60 * 1000)
    public void expireVerificationCode() {
        List<VerificationCode> verificationCodeList = verificationCodeMapper.selectList(new QueryWrapper<VerificationCode>().eq("status", VerificationCodeStatus.UNUSED));
        for (VerificationCode verificationCode : verificationCodeList) {
            if (verificationCode.getSendTime().getTime() + 10 * 60 * 1000 < System.currentTimeMillis()) {
                verificationCode.setStatus(VerificationCodeStatus.EXPIRED);
                verificationCodeMapper.updateById(verificationCode);
            }
        }
    }

    /**
     * 验证验证码
     * @param userIdentifier 用户标识
     * @param businessType 业务类型
     * @param code 验证码
     * @return 验证结果
     */
    @Override
    public Boolean verifyVerificationCode(String userIdentifier, BusinessType businessType, String code) {
        // 1. 验证用户标识
        ThrowUtils.throwIf(StrUtil.isBlank(userIdentifier), ErrorCode.BAD_REQUEST);
        ThrowUtils.throwIf(StrUtil.isBlank(businessType.getCode()), ErrorCode.BAD_REQUEST);
        ThrowUtils.throwIf(StrUtil.isBlank(code), ErrorCode.BAD_REQUEST);

        log.info("验证码: {}", code);
        log.info("用户标识: {}", userIdentifier);
        log.info("业务类型: {}", businessType.getCode());
        //2. 查询验证码
        VerificationCode verificationCode = verificationCodeMapper.selectOne(new QueryWrapper<VerificationCode>()
                .eq("user_identifier", userIdentifier)
                .eq("business_type", businessType.getCode())
                .eq("status", VerificationCodeStatus.UNUSED)
        );
        log.info("查询验证码: {}", verificationCode);
        ThrowUtils.throwIf(verificationCode == null, ErrorCode.NOT_FOUND);
        ThrowUtils.throwIf(!verificationCode.getUserIdentifier().equals(userIdentifier), ErrorCode.NOT_FOUND);
        ThrowUtils.throwIf(!verificationCode.getBusinessType().equals(businessType.getCode()), ErrorCode.NOT_FOUND);
        ThrowUtils.throwIf(!verificationCode.getCode().equals(code), ErrorCode.NOT_FOUND);
        ThrowUtils.throwIf(!verificationCode.getStatus().equals(VerificationCodeStatus.UNUSED.getCode()), ErrorCode.NOT_FOUND);

        verificationCode.setStatus(VerificationCodeStatus.USED);
        boolean updateResult = this.updateById(verificationCode);
        ThrowUtils.throwIf(!updateResult, ErrorCode.NOT_FOUND);
        return true;
    }

    /**
     * 校验用户标识
     * @param userIdentifier 用户标识
     */
    private void checkUserIdentifier(String userIdentifier) {
        //1. 校验是否为空
        if (StrUtil.isEmpty(userIdentifier)) {
            throw new BusinessException(ErrorCode.BAD_REQUEST, "用户标识不能为空");
        }
        //2. 判断是否为手机或者邮箱格式
        if (!Validator.isMobile(userIdentifier) && !Validator.isEmail(userIdentifier)) {
            throw new BusinessException(ErrorCode.BAD_REQUEST, "用户标识格式错误");
        }

    }
}




